---@type owner_base
local owner_base                = import('bt/bt_framework/owner_base')
---@type login_cfg
local login_cfg                 = import('game/config/login_cfg')
---@type map_cfg
local map_cfg                   = import('game/config/map_cfg')
---@type ui
local ui                        = import('game/func/ui')
---@type map
local map                       = import('game/func/map')
---@type dungeon
local dungeon                   = import('game/func/dungeon')
---@type MAIN_TARGET_TYPE_CONFIG
local MAIN_TARGET_TYPE_CONFIG   = import('bt/custom_node/enum_type_cfg/MAIN_TARGET_TYPE_CONFIG')
local MAIN_TARGET_TYPE          = MAIN_TARGET_TYPE_CONFIG.TYPE
---@type common
local common                    = import("game/func/common")
---@type role
local role                      = import("game/func/role")

local trace                     = trace
local map_unit                  = map_unit
local game_unit                 = game_unit
local actor_unit                = actor_unit
local main_ctx                  = main_ctx
local local_player              = local_player

---@class owner
local owner                     = owner_base:new()
owner.check_network_time        = 1600
owner.dungeonCompleteNum        = 0
owner.selectRoleIndex           = 0
owner.ini                       = {}
owner.maxRole                   = 1
owner.repairMoney               = 30000
owner.need_team_num             = -1 -- 需要队伍的成员数量
owner.transferGoldInfo          = {
    gold_transfer_info = {}          -- 转金信息
}
owner.selectDunInfo             = {}
owner.huntInfo                  = {}
owner.dailyTaskInfo             = {}
owner.curMainTargetWeightConfig = {}
owner.targetPos                 = {} -- 目标位置
owner.hunt_sign                 = false

owner.roleInfo                  = {
    [0] = {},
    [1] = {},
    [2] = {},
    [3] = {},
}

owner.isFinishOtherRoleMainTarget = false
function owner:on_init()
    self:add_record_fail_listen(function()
        main_ctx:set_ex_state_ex(1, os.time())
        main_ctx:end_game()
    end)
end

function owner:on_clear_data()
    self.deadCount = 0
    self.timers = {}
    self.lastPos = nil
    self.lastLevel = nil
    self.failNode = {}
    self.recordNumData = {}
    self.repairMoney = 30000
    self.check_network_timer = 0
    self.waitLoadingTimer = 0
    self.need_team_num = -1
    self.curMainTargetWeightConfig = {}
    self.userPath = ""
    self.targetPos = {}
    --self.ini = {}
    --self.notEnterDungeon = nil
end

-- 决策树运行前刷新
function owner:on_update_data(ctx)
    ctx.gameStatus = game_unit.get_game_status_ex()
    local updateInfo = self:get_timer_time("间隔刷新")
    if not updateInfo then
        self:add_timer("间隔刷新", 1.5, nil, false, true, true)
    end
    -- 在15分钟内连续卡点传送3次则执行下线
    local standTransferTimer = self:get_timer_time("卡点传送清空计时")
    if not standTransferTimer then
        self:add_timer("卡点传送清空计时", 15 * 60, nil, false, true, true)
    end
    if not standTransferTimer or standTransferTimer <= 0 then
        self.standTransferCount = 0
    end

    self.curMainTarget = self:get_curMainTarget()

    -- 过图状态判断
    if self.waitLoadingTimer <= 0 and ctx.gameStatus == login_cfg.IN_GAME and ctx.lastGameStatus == login_cfg.LOADING_MAP then
        self.waitLoadingTimer = 4
    end
    -- 等待过图
    if self.waitLoadingTimer > 0 and ctx.gameStatus == login_cfg.IN_GAME then
        self.waitLoadingTimer = self.waitLoadingTimer - 1
        if self.waitLoadingTimer > 0 then
            trace.log_trace('过图后主动延迟.....')
            ctx.gameStatus = login_cfg.LOADING_MAP
        end
    end

    if ctx.gameStatus == login_cfg.IN_GAME then
        if not self.userPath or self.userPath == "" then
            local idx = role.get_role_idx()
            if idx ~= 0 then
                local need_region = main_ctx:c_region_name()
                local need_server = main_ctx:c_server_name()
                self.userPath = need_region .. "_" .. need_server .. "_" .. idx
                self.selectRoleIndex = idx - 1
            end
        end
    end
    -- 站立时间重置
    if ctx.gameStatus ~= login_cfg.IN_GAME or self.curMainTarget ~= MAIN_TARGET_TYPE.DEAD or (self.lastMapId and self.lastMapId == self.mapId) then
        if self.standTime then
            self.standTime = 0
            self.isMoving = false
        end
    end
    -- 刷新角色数据
    if ctx.gameStatus == login_cfg.IN_GAME and self.curMainTarget ~= MAIN_TARGET_TYPE.CLOSE_OTHER_WINDOW then
        self.hp = actor_unit.local_player_hp()
        if self.hp and self.maxHp then
            self.hpPercent = self.hp / self.maxHp * 100
        end
        if not self.pos then
            self.pos = {}
        end
        self.pos.x = local_player:cx()
        self.pos.y = local_player:cy()
        self.pos.z = local_player:cz()

        if self.pos and self.lastPos then
            self.lastDis = common.get_dis_by_pos(self.pos, self.lastPos)
        end
        if not self.standTime then
            self.standTime = 0
        end
        -- 记录站立时间
        if self.lastDis and self.lastDis <= 100 then
            self.isMoving = false
            self.standTime = self.standTime + 1
        else
            self.isMoving = true
            self.standTime = 0
        end
        self.auto_type = actor_unit.get_auto_type()
        if not updateInfo or updateInfo <= 0 then
            self.level = actor_unit:local_player_level()
            self.name = local_player:name()
            self.mp = actor_unit.local_player_mp()
            self.maxHp = actor_unit.local_player_max_hp()
            self.mainMapId = actor_unit.main_map_id()
            self.mapId = actor_unit.map_id()
            self.mapName = actor_unit.map_name()
        end
        -- 根据配置的角色目标，刷新目标权重
        if #self.curMainTargetWeightConfig <= 0 or self.level ~= self.lastLevel then
            local tmpCfg = self.main_target_weight_config
            for k, _ in pairs(self.curMainTargetWeightConfig) do
                self.curMainTargetWeightConfig[k] = nil
            end
            local level = self.level
            for _, v in ipairs(tmpCfg) do
                if v.minLevel <= level and v.maxLevel > level then
                    -- 其他角色只做配置的目标
                    if self.selectRoleIndex ~= 0 then
                        for i = 1, #v.config do
                            local isSet = v.config[i].isSet
                            if isSet then
                                table.insert(self.curMainTargetWeightConfig, v.config[i])
                            end
                        end
                    else
                        -- TODO:根据需求，第一角色是优先做配置的需求目标，还是随机权重做配置的所有目标
                        if not self.isFinishOtherRoleMainTarget then
                            for i = 1, #v.config do
                                local isSet = v.config[i].isSet
                                if isSet then
                                    table.insert(self.curMainTargetWeightConfig, v.config[i])
                                end
                            end
                        end
                    end
                end
            end
            -- 第一角色已做完isSet的目标
            if table.is_empty(self.curMainTargetWeightConfig) then
                for _, v in ipairs(tmpCfg) do
                    for i = 1, #v.config do
                        if v.minLevel <= level and v.maxLevel > level then
                            table.insert(self.curMainTargetWeightConfig, v.config[i])
                        end
                    end
                end
            end
        end
        if ctx.gameStatus == login_cfg.IN_GAME and self.mapId then
            if not common.is_exist_list_arg(map_cfg.NOT_CHECK_NETWORK, self.mapId) then
                self:check_netWork(ctx)
            end
        end
        -- 卡点检测
        if ctx.gameStatus == login_cfg.IN_GAME and self.curMainTarget ~= MAIN_TARGET_TYPE.DUNGEON and self.curMainTarget ~= MAIN_TARGET_TYPE.HUNT and self.curMainTarget ~= MAIN_TARGET_TYPE.MAIN_TASK and self.curMainTarget ~= MAIN_TARGET_TYPE.MAIN_TASK_2 and self.curMainTarget ~= MAIN_TARGET_TYPE.NORMAL_TASK and self.curMainTarget ~= MAIN_TARGET_TYPE.DAILY_TASK and self.curMainTarget ~= MAIN_TARGET_TYPE.WORLD_BOSS and self.curMainTarget ~= MAIN_TARGET_TYPE.RECEIVE_WORLD_BOSS_GIFT and self.curMainTarget ~= MAIN_TARGET_TYPE.CLOSE_OTHER_WINDOW and self.curMainTarget ~= MAIN_TARGET_TYPE.NONE then
            -- 3s一次
            local str = ""
            if self.standTime >= 400 and self.curMainTarget or self.standTransferCount >= 3 then
                str = string.format("当前目标 = %s，站立时间 = %d，执行下线并标志完成", self.curMainTarget, self.standTime)
                trace.log_warn(str)
                trace.output(str)
                local lastTime = os.time() - 43200
                -- 半天时间
                main_ctx:set_ex_state_ex(1, lastTime)
                main_ctx:end_game()
                -- 10分钟
            elseif self.standTime >= 200 then
                self.standTransferCount = self.standTransferCount + 1
                if self.mapId ~= 101 and self.curMainTarget then
                    str = string.format("当前目标 = %s，站立时间 = %d，执行回城", self.curMainTarget, self.standTime)
                    trace.log_warn(str)
                    trace.output(str)
                    local transferId = map.get_transfer_id_by_mapId(101)
                    self.standTime = 0
                    map_unit.transfer_to_map(transferId)
                end
            end
        end
    end
end

-- 检查网路
function owner:check_netWork(ctx)
    if self.hp and self.hp > 0 then
        -- 网络异常检测
        self.check_network_timer = self.check_network_timer + 1
        if self.check_network_timer >= self.check_network_time then
            --trace.output('网络检查..........')
            trace.log_trace('网络检查..........')
            if self.check_network_timer == self.check_network_time then
                ui.click_window_btn('是否可见频道列表')
            elseif self.check_network_timer - self.check_network_time == 2 then
                if actor_unit.is_open_channle_shift_widget() then
                    local channelNum = actor_unit.get_widget_channel_num()
                    if channelNum <= 0 then
                        trace.log_trace('获取频道数量失败，开始下线')
                        --trace.output('获取频道数量失败，开始下线')
                        main_ctx:end_game()
                        main_ctx:set_ex_state_ex(1, os.time())
                    end
                else
                    if not dungeon.is_in_dungeon(self) and self.standTime >= 1200 then
                        trace.output("原地站立时间太长，开始下线")
                        trace.log_trace("原地站立时间太长，开始下线")
                        main_ctx:end_game()
                        main_ctx:set_ex_state_ex(1, os.time())
                    end
                end
                --trace.output('检查频道数量')
                trace.log_trace('检查频道数量')
            elseif self.check_network_timer - self.check_network_time >= 3 then
                if actor_unit.is_open_channle_shift_widget() then
                    --trace.output('关闭频道列表')
                    trace.log_trace('关闭频道列表')
                    ui.click_window_btn('是否可见频道列表')
                end
                self.check_network_timer = 0
            end
        end
    end
end

-- 决策树运行后 行为树运行前刷新
function owner:on_before_update_state(stateName, ctx)
    local dungeonAttackTimer = self:get_timer_time("副本被攻击计时")
    if not dungeonAttackTimer then
        local dungeonTime = 30 * 60
        if self.level and self.level >= 45 then
            dungeonTime = 60 * 60
        end
        self:add_timer("副本被攻击计时", dungeonTime, nil, false, true, true)
    end
    local battlePlaceAttackTimer = self:get_timer_time("激战地被攻击计时")
    if not battlePlaceAttackTimer then
        local battlePlaceTime = 30 * 60
        if self.level and self.level >= 45 then
            battlePlaceTime = 60 * 60
        end
        self:add_timer("激战地被攻击计时", battlePlaceTime, nil, false, true, true)
    end
    -- 副本
    if not dungeonAttackTimer or dungeonAttackTimer <= 0 then
        if self.recordData.recordAttackedCount then
            if self.recordData.recordAttackedCount > 0 then
                self.recordData.recordAttackedCount = 0
            end
        else
            self.recordData.recordAttackedCount = 0
        end
    end
    -- 激战地
    if not battlePlaceAttackTimer or battlePlaceAttackTimer <= 0 then
        if self.recordData.recordBattleHuntAttackedCount then
            if self.recordData.recordBattleHuntAttackedCount > 0 then
                self.recordData.recordBattleHuntAttackedCount = 0
            end
        else
            self.recordData.recordBattleHuntAttackedCount = 0
        end
    end

    if stateName == MAIN_TARGET_TYPE.CLOSE_OTHER_WINDOW then
        local closeWindowRunTime = self:get_curState_runTime()
        --trace.log_trace("关闭窗口运行时间:" .. closeWindowRunTime)
        if closeWindowRunTime >= 25 then
            trace.log_warn("关闭窗口运行时间过长，执行ESC退出")
            role.key_control("KEY_Esc")
            if item_unit.is_open_inventory() then
                item_unit.close_inventory()
            end
            self:set_cur_main_target_complete_state(true)
            self:remove_main_target(self:get_lastMainTarget())
        end
    end

    if stateName ~= MAIN_TARGET_TYPE.HUNT then
        owner.hunt_sign = false
    end

    -- 还需要增加判断是在副本中
    if stateName == MAIN_TARGET_TYPE.DUNGEON then
        math.randomseed(os.time() + os.clock())
        local randomNum = math.random(800, 1200)
        ctx:setDeltaTime(randomNum)
        if self.hp and self.maxHp and self.mapId then
            local hpPercent = self.hp / self.maxHp * 100
            if common.is_exist_list_arg(map_cfg.DUNGEON_MAP_ID, self.mapId) then
                if hpPercent < 80 then
                    local name = self.name or ""
                    trace.log_info(name .. "：副本中血量低于80，执行退出")
                    if self.recordData.recordAttackedCount then
                        self.recordData.recordAttackedCount = self.recordData.recordAttackedCount + 1
                        hpPercent = math.floor(hpPercent)
                        trace.log_warn("副本中被攻击次数:" .. self.recordData.recordAttackedCount, "当前血量百分比:" .. hpPercent,
                            "执行传送回城")
                    end
                    local transferId = map.get_transfer_id_by_mapId(101)
                    map_unit.transfer_to_map(transferId)
                    self:set_cur_main_target_complete_state(true)
                end
            end
        end
    elseif stateName == MAIN_TARGET_TYPE.HUNT_BATTLEPLACE then
        local randomNum = math.random(800, 1200)
        ctx:setDeltaTime(randomNum)
        if self.hp and self.maxHp then
            local hpPercent = self.hp / self.maxHp * 100
            if hpPercent < 80 then
                local name = self.name or ""
                trace.log_info(name .. "：激战地挂机中血量低于80，执行退出")
                if self.recordData.recordBattleHuntAttackedCount then
                    self.recordData.recordBattleHuntAttackedCount = self.recordData.recordBattleHuntAttackedCount + 1
                    hpPercent = math.floor(hpPercent)
                    trace.log_warn("激战地挂机中被攻击次数:" .. self.recordData.recordBattleHuntAttackedCount,
                        "当前血量百分比:" .. hpPercent,
                        "执行传送回城")
                end
                local transferId = map.get_transfer_id_by_mapId(101)
                map_unit.transfer_to_map(transferId)
                self:set_cur_main_target_complete_state(true)
            end
        end
    end
end

-- 所有树运行结束刷新
function owner:on_last_update_data(ctx)
    ctx.lastGameStatus = ctx.gameStatus
    if ctx.gameStatus == login_cfg.IN_GAME and self.curMainTarget ~= MAIN_TARGET_TYPE.CLOSE_OTHER_WINDOW then
        if not self.lastPos then
            self.lastPos = {}
        end
        self.lastPos.x = self.pos.x
        self.lastPos.y = self.pos.y
        self.lastPos.z = self.pos.z
        self.lastLevel = self.level
        self.lastHp = self.hp
        self.lastMapId = self.mapId
    end
end

-- 是否组队状态
function owner:is_team_up_state()
    return self.need_team_num > 0
end

-- 清理组队状态
function owner:clear_team_up_state()
    self.need_team_num = -1
end

-- 是否是同一目标
function owner:is_same_targetPos(x, y, z)
    return self.targetPos and x == self.targetPos.x and y == self.targetPos.y and z == self.targetPos.z
end

-- 设置目标坐标
function owner:set_targetPos(x, y, z)
    self.targetPos.x = x
    self.targetPos.y = y
    self.targetPos.z = z
end

return owner
